package com.cxk.hr.security;

import java.util.List;

import javax.annotation.Resource;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.stereotype.Component;

import com.cxk.hr.pojo.Employee;
import com.cxk.hr.pojo.Permis;
import com.cxk.hr.pojo.Role;
import com.cxk.hr.service.EmployeeService;
import com.cxk.hr.service.PermisService;
import com.cxk.hr.service.RoleService;

/**
 * 重写授权和认证
 * 
 * @author 84157
 */
@Component(value = "securityRealm")
public class SecurityRealm extends AuthorizingRealm {
	@Resource
	private EmployeeService employeeService;
	@Resource
	private RoleService roleService;
	@Resource
	private PermisService permisService;

	/*
	 * 权限
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		System.out.println("------------开始权限");
		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
		String userCode = String.valueOf(principals.getPrimaryPrincipal());
		// 获取用户角色
		final List<Role> roleInfos = roleService.selectRolesByUserCode(userCode);
		if (roleInfos != null) {
			for (Role role : roleInfos) {
				// 添加角色
				System.err.println(role);
				authorizationInfo.addRole(role.getRole_sign());
				// 取权限
				System.out.println("--role.getId()" + role.getId());
				final List<Permis> permissions = permisService.selectPermissionsByRoleId(role.getId());
				if (permissions != null) {
					for (Permis permission : permissions) {
						// 添加权限
						System.err.println("---permission" + permission);
						authorizationInfo.addStringPermission(permission.getPermission_sign());
					}
				}
			}
		}
		// 取用户权限
		final List<Permis> userpermissions = permisService.selectPermissionsByUserCode(userCode);
		for (Permis permission : userpermissions) {
			// 添加权限
			System.err.println("---permission" + permission);
			authorizationInfo.addStringPermission(permission.getPermission_sign());
		}

		return authorizationInfo;
	}

	/*
	 * 认证检验 封装返回给校验类的SimpleAuthenticationInfo类
	 * 
	 * 一般是三步,分别是获取数据库中的用户账号,密码以及当前realm对象的name
	 * 
	 * SimpleAuthenticationInfo info = new
	 * SimpleAuthenticationInfo(principal,hashedCredentials,realmName)
	 * 
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		String usercode = String.valueOf(token.getPrincipal());
		String password = new String((char[]) token.getCredentials());

		// 根据usercode(即输入的账号,也就是employee_number)查询员工
		Employee employee = employeeService.selectByNumber(Integer.parseInt(usercode));
		if (employee == null) {
			// 根据employee_number找不到员工,抛出账号找不到异常
			throw new UnknownAccountException();
		}
		// 数据如果为md5加密,则需要和配制文件中的<property name="hashAlgorithmName"
		// value="md5"/>规则保持一致\
		// 加密方法: Object result = new
		// SimpleHash(hashAlgorithmName,crdentials,salt,hashIterations);
		// hashAlgorithmName:加密方式
		// crdentials:密码原值
		// salt:盐值
		// hashIterations:加密次数

		// 盐值加密,对于盐值credentialsSalt，在Shiro中为org.apache.shiro.util.ByteSource对象
		// ByteSource提供了一个内部方法,可以将字符串转换为对应的盐值信息
		// 一般情况下我们使用一个唯一的字符串作为盐值(用户名,id等)
		// 将字符串转换为盐值的方法:(将员工的employee_number转换为盐值)
		ByteSource salt = ByteSource.Util.bytes(Integer.toString(employee.getEmployeeNumber()));

		// 如果我们要对密码进行MD5加盐操作，我们的返回值就不能是SimpleAuthenticationInfo的简单构造
		// 方法了，要使用最复杂的，带有盐值参数的构造方法
		// SimpleAuthenticationInfo info = new
		// SimpleAuthenticationInfo(principal,hashedCredentials,salt,realmName);
		SimpleAuthenticationInfo Info = new SimpleAuthenticationInfo(usercode, employee.getPassword(), salt, getName());

		// 返回给校验类
		return Info;

	}

}
